using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using HslCommunication.Core.Net;
using HslCommunication.LogNet;

namespace HslCommunication.Enthernet
{
	/// <summary>
	/// 用于服务器支持软件全自动更新升级的类<br />
	/// Class for server support software full automatic update and upgrade
	/// </summary>
	public sealed class NetSoftUpdateServer : NetworkServerBase
	{
		private string m_FilePath = "C:\\HslCommunication";

		private string updateExeFileName;

		/// <summary>
		/// 系统升级时客户端所在的目录，默认为C:\HslCommunication
		/// </summary>
		public string FileUpdatePath
		{
			get
			{
				return m_FilePath;
			}
			set
			{
				m_FilePath = value;
			}
		}

		/// <summary>
		/// 实例化一个默认的对象<br />
		/// Instantiate a default object
		/// </summary>
		/// <param name="updateExeFileName">更新程序的名称</param>
		public NetSoftUpdateServer(string updateExeFileName = "软件自动更新.exe")
		{
			this.updateExeFileName = updateExeFileName;
		}

		/// <inheritdoc />
		protected override async void ThreadPoolLogin(Socket socket, IPEndPoint endPoint)
		{
			try
			{
				OperateResult<byte[]> receive = await ReceiveAsync(socket, 4);
				if (!receive.IsSuccess)
				{
					base.LogNet?.WriteError(ToString(), "Receive Failed: " + receive.Message);
					return;
				}
				byte[] ReceiveByte = receive.Content;
				int Protocol = BitConverter.ToInt32(ReceiveByte, 0);
				if (Protocol == 4097 || Protocol == 4098)
				{
					if (Protocol == 4097)
					{
						base.LogNet?.WriteInfo(ToString(), StringResources.Language.SystemInstallOperater + ((IPEndPoint)socket.RemoteEndPoint).Address.ToString());
					}
					else
					{
						base.LogNet?.WriteInfo(ToString(), StringResources.Language.SystemUpdateOperater + ((IPEndPoint)socket.RemoteEndPoint).Address.ToString());
					}
					if (Directory.Exists(FileUpdatePath))
					{
						List<string> Files = GetAllFiles(FileUpdatePath, base.LogNet);
						for (int i = Files.Count - 1; i >= 0; i--)
						{
							FileInfo finfo = new FileInfo(Files[i]);
							if (finfo.Length > 200000000)
							{
								Files.RemoveAt(i);
							}
							if (Protocol == 4098 && finfo.Name == updateExeFileName)
							{
								Files.RemoveAt(i);
							}
						}
						string[] files = Files.ToArray();
						socket.BeginReceive(new byte[4], 0, 4, SocketFlags.None, ReceiveCallBack, socket);
						await SendAsync(socket, BitConverter.GetBytes(files.Length));
						for (int j = 0; j < files.Length; j++)
						{
							FileInfo finfo2 = new FileInfo(files[j]);
							string fileName = finfo2.FullName.Replace(m_FilePath, "");
							if (fileName.StartsWith("\\"))
							{
								fileName = fileName.Substring(1);
							}
							byte[] ByteName = Encoding.Unicode.GetBytes(fileName);
							int First = 8 + ByteName.Length;
							byte[] FirstSend = new byte[First];
							FileStream fs = new FileStream(files[j], FileMode.Open, FileAccess.Read);
							Array.Copy(BitConverter.GetBytes(First), 0, FirstSend, 0, 4);
							Array.Copy(BitConverter.GetBytes((int)fs.Length), 0, FirstSend, 4, 4);
							Array.Copy(ByteName, 0, FirstSend, 8, ByteName.Length);
							await SendAsync(socket, FirstSend);
							Thread.Sleep(10);
							byte[] buffer = new byte[40960];
							int count;
							for (int sended = 0; sended < fs.Length; sended += count)
							{
								count = await fs.ReadAsync(buffer, 0, buffer.Length);
								await SendAsync(socket, buffer, 0, count);
							}
							fs.Close();
							fs.Dispose();
							Thread.Sleep(20);
						}
					}
					else
					{
						await SendAsync(socket, BitConverter.GetBytes(0));
						socket?.Close();
					}
				}
				else
				{
					await SendAsync(socket, BitConverter.GetBytes(10000f));
					Thread.Sleep(20);
					socket?.Close();
				}
			}
			catch (Exception ex2)
			{
				Exception ex = ex2;
				Thread.Sleep(20);
				socket?.Close();
				base.LogNet?.WriteException(ToString(), StringResources.Language.FileSendClientFailed, ex);
			}
		}

		private void ReceiveCallBack(IAsyncResult ir)
		{
			Socket socket = ir.AsyncState as Socket;
			if (socket == null)
			{
				return;
			}
			try
			{
				socket.EndReceive(ir);
			}
			catch (Exception ex)
			{
				base.LogNet?.WriteException(ToString(), ex);
			}
			finally
			{
				socket?.Close();
			}
		}

		/// <summary>
		/// 获取所有的文件信息
		/// </summary>
		/// <param name="dircPath">目标路径</param>
		/// <param name="logNet">日志信息</param>
		/// <returns>文件名的列表</returns>
		public static List<string> GetAllFiles(string dircPath, ILogNet logNet)
		{
			List<string> list = new List<string>();
			try
			{
				list.AddRange(Directory.GetFiles(dircPath));
			}
			catch (Exception ex)
			{
				logNet?.WriteWarn("GetAllFiles", ex.Message);
			}
			string[] directories = Directory.GetDirectories(dircPath);
			foreach (string dircPath2 in directories)
			{
				list.AddRange(GetAllFiles(dircPath2, logNet));
			}
			return list;
		}

		/// <inheritdoc />
		public override string ToString()
		{
			return $"NetSoftUpdateServer[{base.Port}]";
		}
	}
}
